home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / utilit~1 / stcron4.lzh / STCRON4 / COMMAND.C < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-08  |  6.1 KB  |  270 lines

  1. /* CROND & CRONTAB: (c) Kees Lemmens, Netherlands; June 1993.
  2.  
  3.     Programs for ATARI ST (running under MINT) to make it possible
  4.     to run background jobs at regular intervals.
  5.  
  6.     version 1.1: Okt 1993
  7.  
  8.     - Spawned jobs get uid and gid from user who submitted them.
  9.     - Default directory is changed to users homedir.
  10.       (again on special request by Jeroen Berger !)
  11.  
  12.     version 1.1a: Okt 1993
  13.  
  14.     - Fixed ux2dos conversion in open pipe for AT jobs.
  15.  
  16.     Any questions or suggestions about this program can be send to:
  17.     lemmens@dv.twi.tudelft.nl
  18. */
  19.  
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <stdlib.h>
  23. #include <ctype.h>
  24. #include <time.h>
  25. #include <unistd.h>
  26. #include <fcntl.h>
  27. #include <process.h>
  28. #include <signal.h>
  29. #include <pwd.h>
  30. #include <sys\wait.h>
  31.  
  32. #include "cron.h"
  33.  
  34. extern void LogMsg(char *name, int pid, char *fmt,...);
  35. extern char *ux2dos(char *);
  36.  
  37. static char *environ[] = {    "", NULL };
  38. /* Environment is not read by Mintshel so it's in fact useless ! */
  39.  
  40. int sspawnve(int mode,char *cmd, char *argstring, char **envp)
  41. {    char TosArgs[128] = "x";
  42.     int imode;
  43.     
  44. #ifdef DEBUG
  45.     mode = P_WAIT;
  46. #endif
  47.  
  48.     ux2dos(cmd);
  49.     ux2dos(argstring);
  50.  
  51.     strncat(TosArgs,argstring,sizeof(TosArgs) - 1);
  52.     *TosArgs = strlen(argstring);    /* first byte is strlen */
  53.  
  54.     switch(mode)
  55.     {    case P_WAIT    : imode=  0; break;
  56.         case P_NOWAIT  : imode=100; break;
  57.         case P_OVERLAY : imode=200; break;
  58.     }
  59.     
  60.     return (int)Pexec(imode, cmd, TosArgs, (void *)envp);
  61. }
  62.  
  63. void WriteMailHeader(entry *job,FILE *fp)
  64. {    time_t t;
  65.  
  66.     time(&t);
  67.     
  68.     /* first line conform mail headers under UNIX */
  69.  
  70.     fprintf(fp,"From cron %s",ctime(&t));
  71.     fprintf(fp,"To: %s\n",job->User);
  72.     fprintf(fp,"Subject: Output from %s job\n\n",
  73.         job->Type == CRON ? "cron" : "at");
  74.     fprintf(fp,"Command: %s\n\n",job->Command);
  75.  
  76.     fflush(fp);
  77. }
  78.  
  79. int StartJob(entry *job,active *ajob)
  80. {    char cmdstring[MAX_TEMPSTR];
  81.     static counter = 0;    /* for unique filenames */
  82.     struct passwd *pwent;
  83.     FILE *fp;
  84.     int  fd;
  85.  
  86. /* Use a unique filename for output. Tmpnam can't be used, as it 
  87.    also generates $ signs that can confuse the shell !!
  88. */
  89.  
  90. #ifdef DEBUG
  91.     strcpy(ajob->Output,"u:/dev/tty");
  92. #else    
  93.     sprintf(ajob->Output,SPOOLDIR "/%08.8d.crn",counter++);
  94. #endif
  95.  
  96.     strcpy(ajob->User,job->User);
  97.     sprintf(cmdstring,"-c %s; %.*s",DEFPATH,MAX_COMMAND,job->Command);
  98.  
  99.     if ((fp = fopen(ux2dos(ajob->Output),"w")) == NULL)
  100.         return EROUTP;
  101.  
  102.     WriteMailHeader(job,fp);
  103.  
  104.     /* redirect stdout and stderr */
  105.  
  106.     fd=fileno(fp);
  107.     Fforce(1,fd); Fforce(2,fd);
  108.  
  109.     {    if((ajob->Pid =(int)fork()) == 0)
  110.         {
  111.             /* must change uid & gid in a subprocess or it will
  112.                be impossible to change back to uid 0 again !
  113.             */
  114.  
  115.             if((pwent = getpwnam(job->User)) != NULL)
  116.             {    (void)setuid(pwent->pw_uid);
  117.                 (void)setgid(pwent->pw_gid);
  118.  
  119.                 Dsetpath(ux2dos(pwent->pw_dir));
  120.                 /* this assumes we're in drive u: */
  121.             }
  122.  
  123.             sspawnve(P_OVERLAY,SHELLCMD,cmdstring,environ);
  124.  
  125.             exit(1); /* just in case Pexec overlay fails */
  126.         }
  127.     }
  128.  
  129.     if(ajob->Pid < 0)
  130.     {    Fforce(1,0); Fforce(2,0);
  131.         fclose(fp);
  132.         return ERJOB;
  133.     }
  134.     ajob->Status = BUSY;
  135.  
  136.     Fforce(1,0); Fforce(2,0);
  137.     fclose(fp);
  138.     return ajob->Pid;
  139. }
  140.  
  141. void HandleExits(active ajobs[])
  142. {    int nr;
  143.     FILE *fp;
  144.     char cmdstring[MAX_COMMAND];
  145.     union
  146.     {    long l;
  147.         struct { int Pid; int ExitCode; } c;
  148.     } stat;
  149.  
  150.     /* collect all finished jobs */
  151.      
  152.     while((stat.l=Pwait3(WNOHANG,NULL)) > 0L)
  153.     {
  154.         for(nr=0;nr<MAX_SIMJOBS;nr++)
  155.         {    if(ajobs[nr].Pid == stat.c.Pid && ajobs[nr].Status == BUSY)
  156.             {
  157.                 LogMsg(PROGNAME,stat.c.Pid,"Job finished (exit=%d)",
  158.                     stat.c.ExitCode);
  159.  
  160.                 /* append exitcode to mail message */
  161.  
  162.                 if ((fp = fopen(ux2dos(ajobs[nr].Output),"a")) != NULL)
  163.                 {    fprintf(fp,"\nExit code : %d\n",stat.c.ExitCode);
  164.                     fclose(fp);
  165.                 }
  166.                 else
  167.                     LogMsg(PROGNAME,stat.c.Pid,"Can't append to output %s",
  168.                         ajobs[nr].Output);
  169.  
  170.                 ajobs[nr].Status = FINISHED;
  171.             }
  172.         }
  173.     }
  174.  
  175.     /* send output from finished jobs as mail to the user */
  176.  
  177. #ifndef DEBUG
  178.  
  179.     for(nr=0;nr<MAX_SIMJOBS;nr++)
  180.     {
  181.         if(ajobs[nr].Status != FINISHED)
  182.             continue;
  183.         
  184.         sprintf(cmdstring,"-c " MAILCMD " " MAILARG,
  185.             ajobs[nr].Output,ajobs[nr].User);
  186.  
  187.         sspawnve(P_WAIT,SHELLCMD,cmdstring,environ);
  188.  
  189.         /* and AFTER that (!!) remove the outputfile */
  190.                 
  191.         if(remove(ajobs[nr].Output) != 0)
  192.             LogMsg(PROGNAME,stat.c.Pid,"Can't remove output %s",
  193.                 ajobs[nr].Output);
  194.  
  195.         ajobs[nr].Status = FREE;    /* clear status */
  196.     }
  197. #endif
  198. }
  199.  
  200. void RemoveAtJob(entry *job)
  201. {    char atfile[MAX_FNAME];
  202.  
  203.     sprintf(atfile,"%s/%s.%03d",ATDIR,job->User,job->AtId);
  204.     if(remove(ux2dos(atfile)) < 0)
  205.         LogMsg(PROGNAME, getpid(), "Can't remove %s",atfile);
  206. }
  207.  
  208. void DoJobs(entry joblist[], int jobcount, active ajoblist[])
  209. {    int x,n,chpid;
  210.     int cronout;
  211.     char *message,cmd;
  212.  
  213.     for(x=0;x<jobcount;x++)
  214.     {
  215.         if(joblist[x].Status == START)
  216.         {
  217.             for(n=0;n<MAX_SIMJOBS && ajoblist[n].Status != FREE;n++);
  218.  
  219.             /* If no more jobs then don't clear job Status so we'll
  220.                retry next run.
  221.             */
  222.  
  223.             if(n>=MAX_SIMJOBS)
  224.             {    LogMsg(PROGNAME,getpid(),"No more active jobs \"%.10s\" (%s)",
  225.                     joblist[n].Command,joblist[n].User);
  226.                 return;
  227.             }
  228.  
  229.             chpid = StartJob(&joblist[x],&ajoblist[n]);
  230.  
  231.             switch(chpid)
  232.             {    case EROUTP:
  233.                     message="%Job \".15s\" (%s) no output";
  234.                 break;
  235.                 case ERJOB:
  236.                     message="%Job \".15s\" (%s) failed";
  237.                 break;
  238.                 default:
  239.                     joblist[x].Status = SLEEP;
  240.                     switch(joblist[x].Type)
  241.                     {    case CRON :
  242.                             message="CRON job \"%.10s\" (%s) started";
  243.                         break;
  244.                         case AT   :
  245.                             message="AT job \"%.10s\" (%s) started";
  246.  
  247.                             /* job can be removed: only one run */
  248.                             if((cronout=open(ux2dos(CRONPIPE),O_WRONLY)) < 0)
  249.                                 LogMsg(PROGNAME,getpid(),
  250.                                     "Internal write to pipe failed");
  251.                             else
  252.                             {    cmd = INTERNBUILD;
  253.                                 write(cronout,&cmd,1);
  254.                                 close(cronout);
  255.                             }
  256.                             RemoveAtJob(&joblist[x]);
  257.                         break;
  258.                     }
  259.                 break;
  260.             }
  261.             LogMsg(PROGNAME,chpid,message,joblist[x].Command,
  262.                 joblist[x].User);
  263.  
  264. #ifdef DEBUG
  265.             DebugPrintTimes(&joblist[x]);
  266. #endif
  267.             
  268.         }
  269.     }
  270. }